perm filename SERVO.FAI[CMS,LCS] blob
sn#469396 filedate 1979-08-25 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00019 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 TITLE SERVO
C00006 00003 Shared ram.
C00009 00004 Start of prom.
C00012 00005 Sets the current position to the converted encoder value, the
C00014 00006 RSTCKW: LDAI 377 Reset check word.
C00017 00007 Clock tick interrupt.
C00019 00008 Interpolate the velocity.
C00021 00009 BITZ MODE If servo is disabled, we're
C00023 00010 INBAND: LDAI LSBENB In band. Is LSB servo enabled?
C00026 00011 LDAZ IVEL-1 Round IVEL by seting the carry to the complement
C00028 00012 DAC output routine.
C00031 00013 CMDTBL: DEFERRED COMMAND TABLE.
C00034 00014 INTINC ← CMDVEL - IVEL. (Velocity difference).
C00036 00015 Position conversion routine.
C00038 00016 Arithmetic routines.
C00041 00017 Enter with sign and characteristic in A, mantissa in Y
C00044 00018 Enter with characteristic of multiplier in A,
C00047 00019 DAC output table.
C00050 ENDMK
C⊗;
TITLE SERVO
.INSERT ASMBL.FAI[CMS,LCS]
;I/O address definitions.
DAC ← 100000 ;8 bit DAC.
JCR ← 120000 ;Joint control output register.
ENCL ← 140000 ;Encoder mux low.
ENCH ← 140001 ;Encoder mux high.
STKSIZ ← 377 ;Stack size.
LSBENB ← 40 ;Enable LSB servo.
;Zero page variables.
;Not shared.
DSPAT: BLOCK 2 ;Dispatch address for commands.
DEFCMD: 0 ;Deferred command.
SAVPOS: BLOCK 2 ;Position for deferred servo command.
CMDVEL: BLOCK 2 ;Commanded velocity.
CURVEL: BLOCK 2 ;Current velocity.
0 ;SETINC-1.
SETINC: BLOCK 2 ;Interpolating increment for setpoints.
0 ;INTINC-1.
INTINC: BLOCK 2 ;Interpolating increment for velocity.
OLDSP: BLOCK 2 ;Last commanded setpoint, for CMDVEL.
POSERR: BLOCK 2 ;Current position error.
INCTR: 0 ;Count the interpolations.
HSTTMR: 0 ;Count ticks between host commands.
LOGTMP: BLOCK 4 ;Temp for the arithmetic routines.
0 ;IVEL-1.
IVEL: BLOCK 2 ;Interpolated velocity.
VPTR: 0 ;Velocity averaging index.
VELTBL: BLOCK 20;Velocity averaging table.
FRICTN: BLOCK 2 ;Friction offset.
ACCEL: BLOCK 2 ;Acceleration term.
ZAPEND ← .-1 ;Clear all the above in startup.
TL: 0 ;Scratch for gray to binary.
TH: 0
MTMP: BLOCK 2 ;Copy of multipilcand from shared memory.
;Shared ram.
LOC 200 ;Second half of zero page.
;STATUS byte bits.
; 7 6 5 4 3 2 1 0
; error check time no bad
; flag word out tick pos
0 ;Locked.
STATUS: 0 ;Flags for the host.
;MODE byte bits.
;Bit 7 6 5 4 3 2 1 0
; servo integ lsb diag
; enlb enlb enbl enbl
0 ;Locked.
MODE: 0 ;Mode bits from host.
CKWORD: BLOCK 2 ;Host I/O check/command word.
CMDPOS: BLOCK 2 ;Commanded position from host.
;IOCTRL byte bits.
;Bit 7 6 5 4 3 2 1 0
; in lsb integ pos
; tol enlb disabl mode
0 ;Locked.
IOCTRL: 0 ;Copy of JCR output port.
CURPOS: BLOCK 2 ;Current position.
0 ;Locked.
NINTER: 0 ;# of interpolations between position commands.
0 ;Locked.
INTSCL: 0 ;# of bits to shift setpoint dif for interpolating.
0 ;Locked.
HSTLIM: 0 ;# of clock ticks allowed between host commands.
VGAIN: BLOCK 2 ;Velocity error gain.
GRAVTY: BLOCK 2 ;DC offset for gravity.
POSTOL: BLOCK 2 ;Half-width of position tolerance band.
INTTOL: BLOCK 2 ;Half-width of integration band.
PGAIN: BLOCK 2 ;Position error gain.
VELERR: BLOCK 2 ;Velocity error.
VSUM: BLOCK 2 ;Sum of last eight velocitys.
0 ;Locked.
FSCL: 0 ;# of right shifts for FRICTN.
BLOCK 2 ;For SETPT-1.
SETPT: BLOCK 2 ;Current setpoint.
0 ;Locked.
DACSIG: 0 ;Last DAC output value.
ACGAIN: BLOCK 2 ;Acceleration gain.
;Start of prom.
LOC 174000
INITBL: STATUS ↔ 0 ;Reset error bits.
NINTER ↔ =16 ;Number of interpolations default.
INTSCL ↔ 4 ;Interpolating scale default.
HSTLIM ↔ =24 ;Ticks before host time out default.
FSCL ↔ =6 ;Shifts for friction.
;13,,100 is 40013 is 1.0.
PGAIN ↔ 13 ;F.P. position gain. Lock.
PGAIN+1 ↔ 100 ;Unlock.
;13,,275 is 136413 is -0.125.
VGAIN ↔ 13 ;F.P. velocity gain. Lock.
VGAIN+1 ↔ 275 ;Unlock.
ACGAIN ↔ 0 ;F.P. acceleration gain. Lock.
ACGAIN+1↔ 0 ;Unlock.
377 ;End of INITBL flag.
;Power on reset.
START: CLD
LDXI STKSIZ ;Setup stack.
TXS
LDAI 0
STA DAC ;Clear DAC.
LDXI ZAPEND
RLOOP: STAZX 0 ;Reset ram.
DEX
BPL RLOOP
LDXI 354 ;-20.
ZSR: STAZX VGAIN+24;Clear shared ram.
INX
BMI ZSR
TAY ;Y ← 0.
BEQ RSTDEF ;Jump
DLOOP: INY
LDAY INITBL ;Init ram.
STAZX 0
INY
RSTDEF: LDXY INITBL
CPXI 377
BNE DLOOP
;Sets the current position to the converted encoder value, the
;setpoint the same, clears the setpoint interpolating increment,
;disables the servo, and waits for a command.
STOP: SEI ;Go into stop mode.
JSR GETPOS ;Read encoder and convert to binary.
STAZ CURPOS ;Set the current position.
STXZ CURPOS+1;Unlock.
STAZ SETPT ;Set the setpoint.
STXZ SETPT+1 ;Unlock.
STAZ OLDSP ;For CMDVEL.
STXZ OLDSP+1
LDAI 71 ;Reset I/O control bits. Position mode off.
STAZ IOCTRL
STA JCR
LDAI 0
STAZ MODE ;Clear position servo enable, etc..
STAZ DEFCMD ;Clear the deferred command flag.
STAZ SETPT-1 ;Clear the setpoint extension
STAZ SETINC-1;and the interpolator.
STAZ SETINC
STAZ SETINC+1
LDXI 27
CLRVEL: STAZX IVEL-1 ;Clear velocity, friction, and acceleration values.
DEX
BPL CLRVEL
STAZ VELERR ;Clear velocity error and sum.
STAZ VELERR+1;Unlock.
STAZ VSUM ;Lock.
STAZ VSUM+1 ;Unlock.
CLI ;End of reset.
RSTCKW: LDAI 377 ;Reset check word.
LDXI 0
SEI
STAZ CKWORD ;Lock.
STXZ CKWORD+1;Unlock.
CLI
;Idle loop. Wait for command.
IDLE: LDAZ CKWORD+1;Check for new check word.
BEQ IDLE ;Not equal if bit 7 is complement of low byte.
SEC
SEI
ADCZ CKWORD ;Lock.
LDXZ CKWORD+1;Unlock.
CLI
TAY
BNE CKWDER ;Check word error.
;Check here for immediate or deferred.
TXA ;Check for valid command.
ORAI 3 ;3 for two commands and bit 0 = 0.
ADCI 0 ;Carry = 1.
BNE CKWDER ;Not a valid command.
;Valid host command.
LDAZ HSTLIM ;Reset host timer.
STAZ HSTTMR
LDAZ DEFCMD ;Check if no TICK?
BNE NOTICK ;No response since last deferred command.
;Check here if posiition command?
SEI
LDYZ CMDPOS ;Read position for servo command.
LDAZ CMDPOS+1;Unlock.
CLI
STYZ SAVPOS ;Save it for later.
STAZ SAVPOS+1
ASLA ;Check for valid position.
BCS CSET
BMI BADPOS
BPL GOODP ;Jump.
CSET: BPL BADPOS
GOODP: STXZ DEFCMD ;Save deferred command pointer.
JMP RSTCKW ;Handshake with host via CKWORD.
CKWDER: LDAI 300 ;Set check word error flag.
WSTAT: ORAZ STATUS
STAZ STATUS
JMP STOP
NOTICK: LDAI 220 ;Set tick error flag.
BNE WSTAT ;Jump.
BADPOS: LDAI 210 ;Set bad position error flag.
BNE WSTAT ;Jump.
;Clock tick interrupt.
TICK: PHA ;Save state.
TXA
PHA
TYA
PHA
INCZ IOCTRL ;Turn on interrupt flag bit.
LDAZ IOCTRL ;This is only for timing checks.
STA JCR ;Can be flushed.
JSR GETPOS ;Read position and convert to binary.
SEC
SBCZ CURPOS ;Subtract the old position
STAZ CURVEL ;yielding the velocity.
TXA ;High byte of binary position.
SBCZ CURPOS+1;Unlock.
STAZ CURVEL+1
STYZ CURPOS ;Update the current position.
STXZ CURPOS+1;Unlock.
DECZ HSTTMR ;Count the ticks since the last command
BPL HOSTOK ;and check for timeout.
LDAI 0 ;Host dead. Stop.
STAZ HSTTMR
STAZ INTINC-1
STAZ INTINC
STAZ INTINC+1
STAZ FRICTN
STAZ FRICTN+1
STAZ ACCEL
STAZ ACCEL+1
LDAI 240 ;Set host time out flag
ORAZ STATUS
STAZ STATUS
LDAI 20 ;Check for diagnostic enable.
BITZ MODE
BNE HOSTOK ;If diagnostics, then servo anyway.
LDAI 177 ;Turn off servo enable.
ANDZ MODE
STAZ MODE
HOSTOK: BITZ MODE ;Check if servo is enabled.
BMI INTVEL
JMP CURSRV ;don't servo.
;Interpolate the velocity.
INTVEL: CLC
LDAZ IVEL-1
ADCZ INTINC-1;IVEL ← IVEL + INTINC.
STAZ IVEL-1
LDAZ IVEL
ADCZ INTINC
STAZ IVEL
LDAZ IVEL+1
ADCZ INTINC+1
STAZ IVEL+1
;Interpolate the setpoints.
INTRS: CLC
LDAZ SETPT-1 ;Unlock.
ADCZ SETINC-1;Add the increment to the setpoint.
STAZ SETPT-1 ;Unlock.
LDAZ SETPT ;Lock.
ADCZ SETINC
TAX ;Save SETPT for lockout.
LDAZ SETPT+1 ;Unlock.
ADCZ SETINC+1
STXZ SETPT ;Lock.
STAZ SETPT+1 ;Unlock.
DECZ INCTR ;Check if this is the last interpolation.
BNE GPOSER
LDAI 0 ;Clear SETINC if done interpolating.
STAZ SETINC-1
STAZ SETINC
STAZ SETINC+1
STAZ INTINC-1;Clear INTINC (commanded velocity).
STAZ INTINC
STAZ INTINC+1
;Calculate the position error.
GPOSER: SEC
LDAZ CURPOS ;POSERR ← CURPOS - SETPT.
LDXZ CURPOS+1;Unlock.
SBCZ SETPT ;Lock.
STAZ POSERR
TXA ;Get CURPOS+1.
SBCZ SETPT+1 ;Unlock.
STAZ POSERR+1
BITZ MODE ;If servo is disabled, we're
BPL OOTOL ;automatically out of tolerance
LDAZ POSERR+1;Test the sign of pos error.
BMI NEGPER
LDAZ POSTOL ;Positive. Compare with tol.
CMPZ POSERR
LDAZ POSTOL+1;Unlock.
SBCZ POSERR+1
BCS TOLOK ;In tolerance.
BCC OOTOL ;Jump.
NEGPER: CLC ;Negative. Add the tolerance.
LDAZ POSTOL ;Lock.
ADCZ POSERR
LDAZ POSTOL+1;Unlock.
ADCZ POSERR+1
BCS TOLOK ;In tolerance.
OOTOL: LDAZ IOCTRL ;Out of tolerance.
ANDI 177 ;Turn off the in tolerance
BNE WCNTRL ;indicator. Jump.
TOLOK: LDAZ IOCTRL ;In tolerance. Turn it on.
ORAI 200
WCNTRL: STAZ IOCTRL
STA JCR ;Copy it to output.
BITZ MODE ;If intergration is disabled,
BVC OOBAND ;turn it off.
LDAZ POSERR+1;Test sign of position error.
BMI ADTOL
LDAZ INTTOL ;Positive. Compare with tol.
CMPZ POSERR
LDAZ INTTOL+1;Unlock.
SBCZ POSERR+1
BCS INBAND ;In band. Turn on integrator.
BCC OOBAND ;Jump.
ADTOL: CLC ;Negative. Add the tolerance.
LDAZ INTTOL ;Lock.
ADCZ POSERR
LDAZ INTTOL+1;Unlock.
ADCZ POSERR+1
BCS INBAND ;Check if in band.
OOBAND: LDAZ IOCTRL ;Out of band. Turn off
ORAI 10 ;integration by setting the
ANDI 357 ;control bit. LSB servo off.
BNE WCTRL2 ;Jump.
INBAND: LDAI LSBENB ;In band. Is LSB servo enabled?
BITZ MODE
BEQ RCNTRL
LDAZ POSERR ;Yes. Is the error exactly 0?
ORAZ POSERR+1
BNE RCNTRL
LDAZ IOCTRL ;It is. Integration off, LSB
ORAI 30 ;servo on.
BNE WCTRL2 ;Jump.
RCNTRL: LDAZ IOCTRL ;LSB disabled or error not zero.
ANDI 347 ;LSB servo off, integration on.
WCTRL2: STAZ IOCTRL
STA JCR ;Output it.
LDXZ PGAIN ;Copy position gain for multiply.
LDYZ PGAIN+1 ;Unlock.
STXZ MTMP
STYZ MTMP+1
LDYZ POSERR
LDAZ POSERR+1
JSR LOG ;Float the position error.
LDXI MTMP ;Point X to copy of PGAIN.
JSR MULTIP ;POSERR ← POSERR * PGAIN.
JSR EXP ;Fix it.
STYZ POSERR
STAZ POSERR+1
;Get the velocity error.
CLC
LDAZ VSUM ;Lock.
ADCZ CURVEL ;VSUM ← VSUM + CURVEL.
TAX
LDAZ VSUM+1 ;Unlock.
ADCZ CURVEL+1
TAY
TXA
LDXZ VPTR ;Get velocity averaging index.
SEC
SBCZX VELTBL ;VSUM ← VSUM - VELTBL[VPTR].
STAZ VSUM ;Lock.
TYA
SBCZX VELTBL+10
STAZ VSUM+1 ;Unlock.
LDAZ CURVEL ;VELTBL[VPTR] ← CURVEL.
STAZX VELTBL
LDAZ CURVEL+1
STAZX VELTBL+10
INX ;VPTR ← (VPTR + 1) .AND. (VTLEN - 1).
TXA
ANDI 7
STAZ VPTR
LDAZ IVEL-1 ;Round IVEL by seting the carry to the complement
EORI 200 ;of bit 7 in IVEL-1.
ROLA
LDAZ VSUM ;Lock.
LDXZ VSUM+1 ;Unlock.
SBCZ IVEL ;VELERR ← VSUM - IVEL.
TAY ;Save VELERR.
STAZ VELERR ;Lock.
TXA ;Get VSUM+1.
SBCZ IVEL+1
STAZ VELERR+1;Unlock.
JSR LOG ;Float the velocity error.
STYZ MTMP ;Save the F.P. VELERR.
STAZ MTMP+1
LDYZ VGAIN ;Get the velocity gain.
LDAZ VGAIN+1 ;Unlock.
LDXI MTMP ;multiply by the velocity error,
JSR MULTIP ;VELERR * VGAIN.
JSR EXP ;Fix it.
TAX ;Save high byte.
CLC
TYA ;Get low byte.
ADCZ POSERR ;Add the position error...
TAY ;Save low byte.
TXA ;Get high byte.
ADCZ POSERR+1
TAX ;Save high byte.
CLC
TYA ;Get low byte.
ADCZ FRICTN ;...the friction offset...
TAY ;Save low byte.
TXA ;Get high byte.
ADCZ FRICTN+1
TAX ;Save high byte.
CLC
TYA ;Get low byte.
ADCZ ACCEL ;...the acceleration term...
TAY ;Save low byte.
TXA ;Get high byte.
ADCZ ACCEL+1
STAZ POSERR+1
CLC ;...and the gravity offset.
TYA ;Get the low byte.
ADCZ GRAVTY ;Lock.
TAY ;Save low byte.
LDAZ GRAVTY+1;Unlock.
ADCZ POSERR+1
;DAC output routine.
;Enter with 2 byte value in Y (low), A (high).
BMI NEGDAC ;Assuming the last inst. loaded A.
CPYI 200 ;Positive. Compare with 2↑7.
SBCI 0
BCC INRNGE
TOOHI: LDYI 177 ;Too high. Saturate positive.
BNE INRNGE ;Jump.
NEGDAC: CPYI 200 ;Negative. Compare with -2↑7.
SBCI 377
BCS INRNGE
TOOLOW: LDYI 200 ;Too low. Saturate to -2↑7.
INRNGE: LDAY VETBL ;Straighting it.
STAZ DACSIG ;Unlock.
STA DAC ;Output 8 bits to the DAC.
CMDSP: LDAZ DEFCMD ;Check for a command.
BEQ INTXIT
ANDI 2 ;Low nibble command bit.
TAX
LDAX CMDTBL ;Get command address.
STAZ DSPAT
LDAX CMDTBL+1
STAZ DSPAT+1
JMPIN DSPAT ;Execute command.
CMDEND: LDAI 0 ;Done with deferred command.
STAZ DEFCMD ;Reset command word.
INTXIT: DECZ IOCTRL ;Turn off interrupt flag.
LDAZ IOCTRL ;Can be flushed.
STA JCR
PLA ;Restore state and dismiss interrupt.
TAY
PLA
TAX
PLA
RTI
;Servo disabled.
CURSRV: LDAI 0
STA DAC ;Turn off the servo valve.
STAZ SETPT-1 ;Make the setpoint track
LDAZ CURPOS ;the current position in order to
STAZ SETPT ;keep the arm from twitching when
LDAZ CURPOS+1;the host enables the servo. Unlock.
STAZ SETPT+1 ;Unlock.
LDAI 373
ANDZ IOCTRL ;Turn off position mode bit.
STAZ IOCTRL
STA JCR
JMP CMDSP ;Go check on commands.
CMDTBL: ;DEFERRED COMMAND TABLE.
CMDEND∧377 ;Nop.
(CMDEND⊗-10)∧377
CMDSRV∧377 ;Servo command.
(CMDSRV⊗-10)∧377
;Deferred commands.
CMDSRV: LDAZ MODE ;Servo command.
BMI ENBLD ;Test for servo enabled.
JMP CMDEND ;No. End this command.
ENBLD: SEC ;Enabled.
LDAZ SAVPOS ;Get commanded position.
SBCZ SETPT ;Get difference between next position
STAZ SETINC ;and the last setpoint.
LDAZ SAVPOS+1
SBCZ SETPT+1 ;Unlock.
LDXI 0
STXZ SETPT-1 ;Clear setpoint and increment extentions.
STXZ SETINC-1
STXZ INTINC-1
LDXZ INTSCL ;A = SETINC+1.
SCAL: CMPI 200 ;Extend sign.
RORA ;Divide the difference by the number of interpolations.
RORZ SETINC
RORZ SETINC-1
DEX
BNE SCAL
STAZ SETINC+1;Which yields the interpolating increment.
LDAZ NINTER
STAZ INCTR ;Setup the interpolator count.
SEC
LDAZ SAVPOS
SBCZ OLDSP ;CMDVEL ← CMDPOS - OLDSP.
STAZ CMDVEL
STAZ FRICTN
LDAZ SAVPOS+1
SBCZ OLDSP+1
TAY ;Save CMDVEL+1.
LDXZ FSCL ;Unlock.
FSCAL: CMPI 200 ;Extend sign and scale FRICTN by FSCL.
RORA
RORZ FRICTN
DEX
BNE FSCAL
BCC NOINC ;Round it.
INCZ FRICTN
BNE NOINC
ADCI 0 ;C = 1.
NOINC: STAZ FRICTN+1
;INTINC ← CMDVEL - IVEL. (Velocity difference).
LDAZ IVEL-1
ROLA ;IVEL * 2.
TAX ;Save it for rounding.
LDAZ IVEL
ROLA
STAZ INTINC
LDAZ IVEL+1
ROLA
STAZ INTINC+1
TXA ;Get IVEL-1 * 2.
BPL COPYG ;Round IVEL * 2.
INCZ INTINC
BNE COPYG
INCZ INTINC+1
COPYG: LDAZ ACGAIN ;Copy this for multiply.
LDXZ ACGAIN+1;Unlock.
STAZ MTMP
STXZ MTMP+1
SEC
LDAZ CMDVEL
SBCZ INTINC ;INTINC ← CMDVEL - (IVEL * 2).
STAZ INTINC
TYA ;Get CMDVEL+1.
SBCZ INTINC+1
STAZ INTINC+1
LDYZ INTINC ;A = INTINC+1.
JSR LOG ;Float the velocity difference.
LDXI MTMP ;Point X to copy of ACGAIN.
JSR MULTIP ;VELDIF * ACGAIN.
JSR EXP ;Fix it.
STYZ ACCEL ;ACCEL ← INTINC * ACGAIN.
STAZ ACCEL+1
LDAZ INTINC+1;INTINC ← (CMDVEL - (IVEL * 2)) / 32.
LDXZ INTSCL
ISCAL: CMPI 200 ;Extend sign and divide by the number of
RORA ;interpolations + 1.
RORZ INTINC
RORZ INTINC-1
DEX
BPL ISCAL
STAZ INTINC+1
LDAZ SAVPOS
STAZ OLDSP ;OLDSP ← CMDPOS.
LDAZ SAVPOS+1
STAZ OLDSP+1
LDAI 44
ORAZ IOCTRL ;Turn on servo and current mode enable bits.
STAZ IOCTRL
STA JCR ;Output it.
JMP CMDEND
;Position conversion routine.
GETPOS: LDY ENCL ;Read encoder.
LDA ENCH
;Convert from gray to binary.
STAZ TH
LSRA ;Shift by 1.
EORZ TH
STAZ TH
TAX ;X ← high byte.
TYA
STAZ TL
RORA
EORZ TL
STAZ TL
LSRZ TH ;Shift by 2.
RORA
LSRZ TH
RORA
EORZ TL
STAZ TL
TAY ;Y ← low byte.
TXA ;Get high byte.
EORZ TH
STAZ TH
LSRA ;Shift by 4.
RORZ TL
LSRA
RORZ TL
LSRA
RORZ TL
LSRA
RORZ TL
EORZ TH
STAZ TH
TYA
EORZ TL
EORZ TH ;Shift by 8.
TAY ;Save low byte.
LDXZ TH ;Get high byte.
BITZ TH
BVC POS ;Check if negative.
TXA
ORAI 200 ;Extend sign.
TAX
POS: TYA ;Returns with position in A, Y (low) and X (high).
RTS
;Arithmetic routines.
;Enter with high byte in A, low in Y.
;Returns A = characteristic and sign, Y = mantissa.
;Clobbers X, LOGTMP, LOGTMP+1.
LOG: STYZ LOGTMP ;Save the inputs.
STAZ LOGTMP+1
LDXI 20+100 ;Init characteristic to 15.
CMPI 0 ;Test sign of input.
BPL POSIN
SEC ;Negative. 2's complement it.
LDAI 0
SBCZ LOGTMP
STAZ LOGTMP
LDAI 0
SBCZ LOGTMP+1
POSIN: BNE NORML ;Is high byte zero?
LDAZ LOGTMP ;Yes. Low byte?
BEQ RTRN ;If so, return zero.
LDYI 0 ;Low nonzero. Shift left one
STYZ LOGTMP ;byte,
LDXI 10+100 ;change characteristic to 7.
NORML: DEX ;Normalize the number, counting the
ASLZ LOGTMP ;characteristic down. When the
ROLA ;first "1" shifts out, we've subtracted
BCC NORML ;1 from the normalized number
ASLZ LOGTMP ;(This rounds the result)
ADCI =11 ;and are left with the fraction
TAY ;Adding 11 to that is equivalent to
TXA ;adding 0.043.
ADCI 0 ;Propagate the carry into the
;characteristic.
ASLA ;Insert the sign bit from the saved
ASLZ LOGTMP+1;input.
RORA
RTRN: RTS ;Done.
;Enter with sign and characteristic in A, mantissa in Y
;Returns 16-bit integer, low byte in Y, high in A.
;Clobbers X, LOGTMP, LOGTMP+1.
EXP: STAZ LOGTMP+1;Save sign of input.
ANDI 177 ;Mask it off.
BEQ ZEROIN ;Zero characteristic returns
TAX ;zero.
TYA ;Get the mantissa...
SEC
SBCI =11 ;...subtract 0.043...
STAZ LOGTMP ;(save this value)
TXA ;...propagate the carry and get rid
SBCI 100 ;of the XS-64 offset.
BMI NEGIN ;If negative (value < 1.0)
;return zero.
CMPI =15 ;Test for overflow (value>=2↑15
BCS SATUR
TAX ;...no. Number is in range.
ADCI 370 ;Is characteristic below 8?
BMI BLOATE
TAX ;No. Reduce if by 8,
JSR UNNORM ;unnormalize.
BMI GETTMP ;Jump.
BLOATE: JSR UNNORM ;Yes. Unnormalize, then
ASLZ LOGTMP ;(round result)
ADCI 0
STAZ LOGTMP ;use result as low byte and
LDAI 0 ;set high byte to zero.
GETTMP: LDYZ LOGTMP
GTMP1: LDXZ LOGTMP+1;Test sign of input...
BPL POSIGN
STAZ LOGTMP+1;...negative. 2's complement
LDAI 0 ;the result.
SEC
SBCZ LOGTMP
TAY
LDAI 0
SBCZ LOGTMP+1
POSIGN: RTS
NEGIN: LDAI 0 ;Set the result to zero if the
ZEROIN: TAY ;input is negative.
RTS
SATUR: LDYI 377 ;Saturate result to 2↑15 - 1 if
STYZ LOGTMP ;input was 15 or more.
LDAI 177
BNE GTMP1 ;Jump.
UNNORM: LDAI 1 ;Unnormalize subroutine. Add 1
BNE DECRX ;to the fraction. Jump.
SCALE: ASLZ LOGTMP ;Scale the fraction left by the
ROLA ;amount of the characteristic.
DECRX: DEX
BPL SCALE
RTS
;Enter with characteristic of multiplier in A,
;mantissa in Y, X pointing to a pair of base page
;locations containing the multiplicand (mantissa in the
;low byte).
;Returns the product in A and Y, same form as the
;multiplier. Leaves X unchanged. Clobbers LOGTMP and
;LOGTMP+1.
MULTIP: PHA
EORZX 1 ;Compute sign of result,
STAZ LOGTMP+1 ;save it away.
PLA
ANDI 177 ;Mask off multiplier sign.
BEQ ZEROIN ;If zero, return zero.
STAZ LOGTMP
TYA ;Add the two logarithms.
CLC
ADCZX 0
TAY
LDAZX 1
ANDI 177 ;If multiplicand is zero,
BEQ ZEROIN ;return a zero.
ADCZ LOGTMP
SEC
SBCI 100 ;Correct the XS-64 offset.
BPL INSIGN ;Result in range?
ANDI 100 ;No. If underflow,
BNE NEGIN ;return zero.
LDAI 177 ;Overflow. Saturate to
LDYI 377 ;highest magnitude.
INSIGN: ASLA ;Insert the sign of the result.
ASLZ LOGTMP+1
RORA
RTS
;Inverse function: 2's complement the magnitude part
;of a 15-bit logarithm.
;Enter with characteristic in A, mantissa in Y.
;Returns inverse in the same form. X unchanged.
;Clobbers LOGTMP and LOGTMP+1.
INV: STYZ LOGTMP ;Pretty straightforward...
STAZ LOGTMP+1
SEC
LDAI 0 ;Complement the number by
SBCZ LOGTMP ;subtracting it from zero.
TAY
LDAI 0
SBCZ LOGTMP+1
JMP INSIGN ;Insert the original sign.
;DAC output table.
LOC (.∨377)+1 ;For start of next page.
VETBL: ;DAC output table.
0 ↔ 20 ↔ 26 ↔ 33 ↔ 37 ↔ 43 ↔ 46 ↔ 50
52 ↔ 54 ↔ 56 ↔ 57 ↔ 60 ↔ 62 ↔ 63 ↔ 64
65 ↔ 66 ↔ 67 ↔ 70 ↔ 71 ↔ 72 ↔ 73 ↔ 74
75 ↔ 76 ↔ 76 ↔ 77 ↔ 100 ↔ 101 ↔ 102 ↔ 103
104 ↔ 104 ↔ 105 ↔ 106 ↔ 107 ↔ 107 ↔ 110 ↔ 111
112 ↔ 112 ↔ 113 ↔ 114 ↔ 115 ↔ 115 ↔ 116 ↔ 117
117 ↔ 120 ↔ 121 ↔ 121 ↔ 122 ↔ 123 ↔ 124 ↔ 124
125 ↔ 126 ↔ 127 ↔ 127 ↔ 130 ↔ 131 ↔ 131 ↔ 132
133 ↔ 133 ↔ 134 ↔ 135 ↔ 135 ↔ 136 ↔ 136 ↔ 137
140 ↔ 140 ↔ 141 ↔ 142 ↔ 142 ↔ 143 ↔ 143 ↔ 144
145 ↔ 145 ↔ 146 ↔ 146 ↔ 147 ↔ 150 ↔ 150 ↔ 151
151 ↔ 152 ↔ 153 ↔ 153 ↔ 154 ↔ 154 ↔ 155 ↔ 156
156 ↔ 157 ↔ 160 ↔ 160 ↔ 161 ↔ 161 ↔ 162 ↔ 162
163 ↔ 164 ↔ 164 ↔ 165 ↔ 165 ↔ 166 ↔ 166 ↔ 167
167 ↔ 170 ↔ 170 ↔ 171 ↔ 171 ↔ 172 ↔ 172 ↔ 173
173 ↔ 174 ↔ 174 ↔ 175 ↔ 176 ↔ 176 ↔ 177 ↔ 177
200 ↔ 200 ↔ 200 ↔ 201 ↔ 201 ↔ 202 ↔ 203 ↔ 203
204 ↔ 204 ↔ 205 ↔ 205 ↔ 206 ↔ 206 ↔ 207 ↔ 207
210 ↔ 210 ↔ 211 ↔ 211 ↔ 212 ↔ 212 ↔ 213 ↔ 213
214 ↔ 215 ↔ 215 ↔ 216 ↔ 216 ↔ 217 ↔ 217 ↔ 220
221 ↔ 221 ↔ 222 ↔ 223 ↔ 223 ↔ 224 ↔ 224 ↔ 225
226 ↔ 226 ↔ 227 ↔ 227 ↔ 230 ↔ 231 ↔ 231 ↔ 232
232 ↔ 233 ↔ 234 ↔ 234 ↔ 235 ↔ 235 ↔ 236 ↔ 237
237 ↔ 240 ↔ 241 ↔ 241 ↔ 242 ↔ 242 ↔ 243 ↔ 244
244 ↔ 245 ↔ 246 ↔ 246 ↔ 247 ↔ 250 ↔ 250 ↔ 251
252 ↔ 253 ↔ 253 ↔ 254 ↔ 255 ↔ 256 ↔ 256 ↔ 257
260 ↔ 260 ↔ 261 ↔ 262 ↔ 262 ↔ 263 ↔ 264 ↔ 265
265 ↔ 266 ↔ 267 ↔ 270 ↔ 270 ↔ 271 ↔ 272 ↔ 273
273 ↔ 274 ↔ 275 ↔ 276 ↔ 277 ↔ 300 ↔ 301 ↔ 301
302 ↔ 303 ↔ 304 ↔ 305 ↔ 306 ↔ 307 ↔ 310 ↔ 311
312 ↔ 313 ↔ 314 ↔ 315 ↔ 317 ↔ 320 ↔ 322 ↔ 323
325 ↔ 327 ↔ 331 ↔ 334 ↔ 340 ↔ 344 ↔ 351 ↔ 357
NMI ← START ;Reset??
;Interrupt vectors.
LOC 177772
NMI∧377
(NMI⊗-10)∧377
START∧377
(START⊗-10)∧377
TICK∧377
(TICK⊗-10)∧377
END